home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / graphics / beztwist.arc / BEZTWIST.C next >
C/C++ Source or Header  |  1986-02-06  |  8KB  |  364 lines

  1. /*    beztwist.c    17-Sep-88
  2. **
  3. **    Display some twisting cubic Bezier curves.
  4. **    Shows speed of code generated by the Turbo C compiler.
  5. **    Works with all 3 resolution modes of the Atari ST.
  6. */
  7.  
  8. #include <tos.h>
  9. #include <stdlib.h>
  10. #include "grtypes.h"
  11.  
  12. #define NULL    ((void *) 0L)
  13. #define NIL    ((void *) -1L)
  14.  
  15.  
  16. typedef struct {
  17.     SCREEN    screen;
  18.     RESOLUTION    res;
  19.     int        planes, words_per_line;
  20.     COLOR    color, col_mask;
  21.     COORD    x_max, y_max;
  22.     long    max_area;
  23. } INFO;
  24.  
  25. typedef struct {
  26.     COORD    x[4];
  27.     COORD    y[4];
  28.     int        active;
  29. } BEZIER;
  30.  
  31. #define    N    10    /* length of FIFO queue */
  32. #define    FLAT    32
  33. #define CONSOLE    2
  34.  
  35. #define    BITS        5
  36. #define SCALE        (1 << BITS)
  37. #define SCALE_2        (1 << (BITS-1))
  38.  
  39.  
  40.  
  41. /*    draw_line()
  42. **
  43. **    Draw a line from point (x_from, y_from) to point (x_to, y_to).
  44. **    Use Bresenham's line drawing algorithm with incremental
  45. **    screen address computation and inline plotting. (Fast!)
  46. */
  47.  
  48. void
  49. draw_line(    register INFO *info,
  50.         COORD x_from, COORD y_from,
  51.         COORD x_to, COORD y_to)
  52. {
  53.     register SCREEN screen;
  54.     COORD delta_x, delta_y, incr_left, incr_left_up;
  55.     COORD count, dist, offset;
  56.     register COLOR color;
  57.     register WORD or_mask, and_mask;
  58.     int flag;
  59.  
  60.     delta_y = y_to - y_from;
  61.     if ((delta_x = x_to - x_from) < 0) {
  62.     delta_x = -delta_x;
  63.     delta_y = -delta_y;
  64.     x_from = x_to;
  65.     y_from = y_to;
  66.     }
  67.     if (delta_y < 0) {
  68.     offset = -info->words_per_line;
  69.     delta_y = -delta_y;
  70.     } else {
  71.     offset = info->words_per_line;
  72.     }
  73.     if (delta_x < delta_y) {
  74.     flag = 1;
  75.     count = delta_y;
  76.     delta_y = delta_x;
  77.     delta_x = count;
  78.     } else {
  79.     flag = 0;
  80.     count = delta_x;
  81.     }
  82.  
  83.     screen =    info->screen +
  84.         ((y_from * info->words_per_line) +
  85.          (x_from >> 4) * info->planes);
  86.     or_mask = 0x8000 >> (x_from & 0x0f);
  87.     incr_left = 2 * delta_y;
  88.     dist = incr_left - delta_x;
  89.     incr_left_up = dist - delta_x;
  90.     color = info->color;
  91.  
  92.     for (;;) {
  93.     and_mask = ~or_mask;
  94.     switch (info->res) {
  95.     case low_res:
  96.         if (color & 8)    screen[3] |= or_mask;
  97.         else        screen[3] &= and_mask;
  98.         if (color & 4)    screen[2] |= or_mask;
  99.         else        screen[2] &= and_mask;
  100.     case med_res:
  101.         if (color & 2)        screen[1] |= or_mask;
  102.         else            screen[1] &= and_mask;
  103.     case hi_res:
  104.         if (color & 1)    screen[0] |= or_mask;
  105.         else        screen[0] &= and_mask;
  106.     default:
  107.         break;
  108.     }
  109.     
  110.     if (count == 0) break;
  111.     count--;
  112.     
  113.     if (dist >= 0) {
  114.         /* Move 1 pixel 'left' and 'up'. */
  115.         dist += incr_left_up;
  116.         or_mask >>= 1;
  117.         screen += offset;
  118.     } else {
  119.         /* Move 1 pixel 'left'. */
  120.         dist += incr_left;
  121.         if (flag)
  122.         screen += offset;
  123.         else
  124.         or_mask >>= 1;
  125.     }
  126.     
  127.     if (or_mask == 0x0000) {
  128.         screen += info->planes;
  129.         or_mask = 0x8000;
  130.     }
  131.     }
  132. }
  133.  
  134.  
  135. /*    bezier()
  136. **
  137. **    Draw the cubic Bezier curve specified by P0, P1, P2 and P3
  138. **    by subdividing it recursively into sub-curves until it
  139. **    can be approximated smoothly by straight line segments.
  140. **    We use fixed point arithmetic to achieve increased precision
  141. **    in coordinate computations. The control points have been
  142. **    scaled with SCALE and 0.5 has been added to the coordinates
  143. **    so that we can feed rounded coordinate values to draw_line().
  144. */
  145.  
  146. void
  147. bezier(    INFO *info,
  148.     long x0, long y0, long x1, long y1,
  149.     long x2, long y2, long x3, long y3)
  150. {
  151.     long v1x, v1y, v2x, v2y, v3x, v3y;
  152.     long vcp1, vcp2, vcp3, area;
  153.     long mid_x, mid_y;
  154.     int code;
  155.  
  156.     /*
  157.     ** Stop the recursion when the size of the area covered
  158.     ** by the convex hull of the Bezier curve is less than or
  159.     ** equal to info->max_area.
  160.     */
  161.  
  162.     /* First, compute direction vectors. */
  163.     v3x = x3 - x0;    v3y = y3 - y0;
  164.     v2x = x2 - x0;    v2y = y2 - y0;
  165.     v1x = x1 - x0;    v1y = y1 - y0;
  166.  
  167.     /* Then, compute vector cross products. */
  168.     code = 0;
  169.     if ((vcp1 = v3x * v2y - v2x * v3y) < 0) code += 4;
  170.     if ((vcp2 = v3x * v1y - v1x * v3y) < 0) code += 2;
  171.     if ((vcp3 = v2x * v1y - v1x * v2y) < 0) code += 1;
  172.  
  173.     /* Finally, compute size of area covered by convex hull.      */
  174.     /* We actually compute 2*area, but that doesn't matter much.  */
  175.     switch (code) {
  176.     case 0:
  177.     case 2:
  178.     case 5:
  179.     case 7:    area = vcp1 + vcp3;    break;
  180.     case 1:
  181.     case 6:    area = vcp2 - vcp3;    break;
  182.     case 3:
  183.     case 4:    area = vcp1 - vcp2;    break;
  184.     default:    return;
  185.     }
  186.     if (code & 4) area = -area;
  187.  
  188.     if (area <= info->max_area) {
  189.     /* Stop recursion and draw a line from P0 to P3. */
  190.     
  191.     /* Rescale and round coordinates before    */
  192.     /* feeding them to draw_line().           */
  193.     draw_line(info,
  194.         x0 >> BITS, y0 >> BITS, x3 >> BITS, y3 >> BITS);
  195.  
  196.     } else {
  197.     /* Area is still too big, so subdivide the curve into    */
  198.     /* two sub-curves and draw these recursively.        */
  199.  
  200.     mid_x = (x0 + 3*x1 + 3*x2 + x3) >> 3;
  201.     mid_y = (y0 + 3*y1 + 3*y2 + y3) >> 3;
  202.     bezier(    info,
  203.         x0, y0,
  204.         (x0 + x1) >> 1, (y0 + y1) >> 1,
  205.         (x0 + 2*x1 + x2) >> 2, (y0 + 2*y1 + y2) >> 2,
  206.         mid_x, mid_y);
  207.     bezier(    info,
  208.         mid_x, mid_y,
  209.         (x1 + 2*x2 + x3) >> 2, (y1 + 2*y2 + y3) >> 2,
  210.         (x2 + x3) >> 1, (y2 + y3) >> 1,
  211.         x3, y3);
  212.     }
  213. }
  214.  
  215.  
  216. /*
  217. **    Show some randomly twisting bezier curves.
  218. */
  219.  
  220. int
  221. main(argc, argv)
  222. int argc;
  223. char *argv[];
  224. {
  225.     INFO    info;
  226.     BEZIER    list[N];
  227.     BEZIER    *q;
  228.     COORD    dx[4], dy[4];
  229.     COORD    *p;
  230.     COLOR    color;
  231.     int        i, j, k, n;
  232.     long    loop = -1, flat = 0;
  233.     
  234.     if (argc >= 2)
  235.     loop = atoi(argv[1]);
  236.     if (loop < 1)
  237.     loop = -1;
  238.     if (argc >= 3)
  239.     flat = atoi(argv[2]);
  240.  
  241.     info.screen = Physbase();
  242.     Setscreen(NIL, NIL, info.res = Getrez());
  243.  
  244.     switch (info.res) {
  245.     case hi_res:
  246.     info.x_max = HI_X_MAX;
  247.     info.y_max = HI_Y_MAX;
  248.     info.planes = HI_PLANES;
  249.     info.words_per_line = HI_WORDS_PER_LINE;
  250.     info.max_area = (flat >= 1 ? flat : FLAT) * SCALE * SCALE;
  251.     info.col_mask = HI_COLORS - 1;
  252.     color = HI_COLORS - 1;
  253.     break;
  254.     case med_res:
  255.     info.x_max = MED_X_MAX;
  256.     info.y_max = MED_Y_MAX;
  257.     info.planes = MED_PLANES;
  258.     info.words_per_line = MED_WORDS_PER_LINE;
  259.     info.max_area = (flat >= 1 ? flat : (3*FLAT)/4) * SCALE * SCALE;
  260.     info.col_mask = MED_COLORS - 1;
  261.     color =  MED_COLORS - 1;
  262.     break;
  263.     case low_res:
  264.     info.x_max = LOW_X_MAX;
  265.     info.y_max = LOW_Y_MAX;
  266.     info.planes = LOW_PLANES;
  267.     info.words_per_line = LOW_WORDS_PER_LINE;
  268.     info.max_area = (flat >= 1 ? flat : FLAT/2) * SCALE * SCALE;
  269.     info.col_mask = LOW_COLORS - 1;
  270.     color = LOW_COLORS - 1;
  271.     break;
  272.     default:
  273.     return -1;
  274.     }
  275.  
  276.     for (i = 1; i < N; i++)
  277.     list[i].active = 0;
  278.  
  279.     i = 0;
  280.     q = &(list[0]);
  281.     q->active = 1;
  282.     for (k = 0; k < 4; k++) {
  283.     q->x[k] = Random() % (info.x_max + 1);
  284.     q->y[k] = Random() % (info.y_max + 1);
  285.  
  286.     n = (Random() & 15) - 7;
  287.     if (n == 0) n = 1;
  288.     else if (n == 8) n = -1;
  289.     dx[k] = n;
  290.     
  291.     n = (Random() & 15) - 7;
  292.     if (n == 0) n = 1;
  293.     else if (n == 8) n = -1;
  294.     dy[k] = n;
  295.     }
  296.  
  297.     while (loop--) {
  298.     info.color = color;
  299.     bezier(    &info,
  300.         q->x[0] * SCALE + SCALE_2, q->y[0] * SCALE + SCALE_2,
  301.         q->x[1] * SCALE + SCALE_2, q->y[1] * SCALE + SCALE_2,
  302.         q->x[2] * SCALE + SCALE_2, q->y[2] * SCALE + SCALE_2,
  303.         q->x[3] * SCALE + SCALE_2, q->y[3] * SCALE + SCALE_2);
  304.  
  305.     j = i;
  306.     i = (i + 1) % N;
  307.     q = &(list[i]);
  308.  
  309.         if (q->active) {
  310.         info.color = 0;
  311.         bezier(    &info,
  312.         q->x[0] * SCALE + SCALE_2, q->y[0] * SCALE + SCALE_2,
  313.         q->x[1] * SCALE + SCALE_2, q->y[1] * SCALE + SCALE_2,
  314.         q->x[2] * SCALE + SCALE_2, q->y[2] * SCALE + SCALE_2,
  315.         q->x[3] * SCALE + SCALE_2, q->y[3] * SCALE + SCALE_2);
  316.     }
  317.  
  318.     q->active = 1;
  319.  
  320.     for (k = 0; k < 4; k++) {
  321.         p = &(q->x[k]);
  322.         *p = list[j].x[k] + dx[k];
  323.         if (*p < 0) {
  324.         *p += 8;
  325.         dx[k] = -dx[k];
  326.         } else if (*p > info.x_max) {
  327.         *p -= 8;
  328.         dx[k] = -dx[k];
  329.         }
  330.  
  331.         p = &(q->y[k]);
  332.         *p = list[j].y[k] + dy[k];
  333.         if (*p < 0) {
  334.         *p += 8;
  335.         dy[k] = -dy[k];
  336.         } else if (*p > info.y_max) {
  337.         *p -= 8;
  338.         dy[k] = -dy[k];
  339.         }
  340.     }
  341.  
  342.     if ((loop & 0xff) == 0) {
  343.         /* change direction */
  344.         k = Random() & 3;
  345.         n = (Random() & 15) - 7;
  346.         if (n == 0)